package com.wulis.common.handler;

import static com.wulis.common.model.enums.HttpStatusEnum.ILLEGAL_ARGUMENT;
import static com.wulis.common.model.enums.HttpStatusEnum.NO_PERMISSION;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.wulis.common.exception.BusinessException;
import com.wulis.common.wrapper.ApiWrapMapper;
import com.wulis.common.wrapper.ApiWrapper;

import lombok.extern.slf4j.Slf4j;

/**
 * @author wuligao
 * @date 2020/3/27 13:32
 */
@Slf4j
@RestControllerAdvice
public class ApiExceptionHandler {
    
    /**
     * 非法参数异常（拦截springframework.validation.BindException）
     *
     * @param e BindException
     * @return ApiWrapper<Object>
     */
    @ExceptionHandler(BindException.class)
    public ApiWrapper<Object> bindHandler(BindException e) {
        FieldError fieldError = e.getBindingResult().getFieldError();
        if (fieldError != null) {
            log.error("'" + fieldError.getField() + "'" + fieldError.getDefaultMessage());
            return ApiWrapMapper.wrap(ILLEGAL_ARGUMENT.code(),
                ILLEGAL_ARGUMENT.message() + ":'" + fieldError.getField() + "'" + fieldError.getDefaultMessage());
        }
        else {
            log.error(e.getMessage());
            return ApiWrapMapper.wrap(ILLEGAL_ARGUMENT.code(), ILLEGAL_ARGUMENT.message() + ":" + e.getMessage());
        }
    }
    
    /**
     * 非法参数异常（拦截springframework.web.bind.MethodArgumentNotValidException）
     *
     * @param e MethodArgumentNotValidException
     * @return ApiWrapper<Object>
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiWrapper<Object> methodArgumentNotValidHandler(MethodArgumentNotValidException e) {
        FieldError fieldError = e.getBindingResult().getFieldError();
        if (fieldError == null) {
            log.error(e.getMessage());
            return ApiWrapMapper.wrap(ILLEGAL_ARGUMENT.code(), ILLEGAL_ARGUMENT.message() + ":" + e.getMessage());
        }
        else {
            log.error("'" + fieldError.getField() + "'" + fieldError.getDefaultMessage());
            return ApiWrapMapper.wrap(ILLEGAL_ARGUMENT.code(),
                ILLEGAL_ARGUMENT.message() + ":'" + fieldError.getField() + "'" + fieldError.getDefaultMessage());
        }
    }
    
    /**
     * 算数异常
     * 
     * @param e ArithmeticException
     * @return ApiWrapper<Object>
     */
    @ExceptionHandler(ArithmeticException.class)
    public ApiWrapper<Object> arithmeticHandler(ArithmeticException e) {
        log.error(e.getMessage());
        return ApiWrapMapper.error("运算异常:" + e.getMessage());
    }
    
    /**
     * 空指针异常
     *
     * @param e NullPointerException
     * @return ApiWrapper<Object>
     */
    @ExceptionHandler(NullPointerException.class)
    public ApiWrapper<Object> nullPointHandler(NullPointerException e) {
        log.error(e.getMessage());
        return ApiWrapMapper.error("空指针异常:" + e.getMessage());
    }
    
    /**
     * 权限不足异常拦截，当security方法级权限不足时抛出该异常
     * 
     * @param e AccessDeniedException
     * @return ApiWrapper<Object>
     */
    @ExceptionHandler(AccessDeniedException.class)
    public ApiWrapper<Object> accessDeniedHandler(AccessDeniedException e) {
        log.warn(e.getMessage());
        return ApiWrapMapper.wrap(NO_PERMISSION);
    }
    
    /**
     * 业务异常
     * 
     * @param e BusinessException
     * @return ApiWrapper<Object>
     */
    @ExceptionHandler(BusinessException.class)
    public ApiWrapper<Object> businessHandler(BusinessException e) {
        log.error(e.getMessage());
        return ApiWrapMapper.wrap(e.getCode(), e.getMessage());
    }
    
    /**
     * 最大的exception异常拦截要放到最后
     * 
     * @param e Exception
     * @return ApiWrapper<Object>
     */
    @ExceptionHandler(Exception.class)
    public ApiWrapper<Object> exceptionHandler(Exception e) {
        log.error(e.getMessage());
        return ApiWrapMapper.error("内部异常:" + e.getMessage());
    }
    
}
